// Package evaluator: 内置函数 - 内置的可以直接使用的函数; 求值函数 - 将 ast.Node 解析转换为 object.Object;
package evaluator

import (
	"fmt"
	"z-lang/ast"
	"z-lang/object"
)

var (
	EMPTY = &object.Empty{}
	NULL  = &object.Null{}
	TRUE  = &object.Boolean{Value: true}
	FALSE = &object.Boolean{Value: false}
)

// Eval 求值函数. 输入一个ast.Node返回一个object.Object
func Eval(node ast.Node, env *object.Environment) object.Object {
	switch node := node.(type) {
	// AST树入口
	case *ast.Program:
		return evalProgram(node, env)
	// 表达式语句
	case *ast.ExpressionStatement:
		return Eval(node.Expression, env)
	// if表达式
	case *ast.IFExpression:
		return evalIfExpression(node, env)
	// 代码块语句
	case *ast.BlockStatement:
		return evalBlockStatements(node, env)
	// 整数表达式
	case *ast.IntegerLiteral:
		return &object.Integer{Value: node.Value}
	// bool字面量表达式
	case *ast.Boolean:
		return boolToBooleanObj(node.Value)
	// 前缀表达式 - 先解析出右边的值，然后根据左边的操作符取反
	case *ast.PrefixExpression:
		right := Eval(node.Right, env)
		if isError(right) {
			return right
		}
		return evalPrefixExpression(node.Operator, right)
	// 中缀表达式 - 先解析左右两边的值，然后根据操作符结合左右值求值
	case *ast.InfixExpression:
		left := Eval(node.Left, env)
		if isError(left) {
			return left
		}
		right := Eval(node.Right, env)
		if isError(right) {
			return right
		}
		return evalInfixExpression(left, node.Operator, right)
	// return 表达式 - 直接解析return右边的表达式
	case *ast.ReturnStatement:
		val := Eval(node.ReturnValue, env)
		if isError(val) {
			return val
		}
		return &object.ReturnValue{Value: val}
	// let 语句
	case *ast.LetStatement:
		eval := Eval(node.Value, env)
		if isError(eval) {
			return eval
		}
		env.Set(node.Name.Value, eval)
	// 标识符
	case *ast.Identifier:
		return evalIdentifier(node, env)
	// 求函数字面量的值，得到函数对象
	case *ast.FunctionLiteral:
		params := node.Parameters
		body := node.Body
		return &object.Function{Parameters: params, Body: body, Env: env}
	// 求函数调用的值
	case *ast.CallExpression:
		// 解析方法
		fn := Eval(node.Function, env)
		if isError(fn) {
			return fn
		}
		// 解析参数
		args := evalExpressions(node.Arguments, env)
		if len(args) == 1 && isError(args[0]) {
			return args[0]
		}
		// 执行函数
		return applyFunction(fn, args)
	// 求字符串字面量的值, 将字符串字面量转换为object.String
	case *ast.StringLiteral:
		return &object.String{Value: node.Value}
	// 求数组字面量的值, 将数组字面量转换为object.Array
	case *ast.ArrayLiteral:
		ele := evalExpressions(node.Elements, env)
		if len(ele) == 1 && isError(ele[0]) {
			return ele[0]
		}
		// 数组只允许存储相同类型的元素, 对于元素大于1个的数组，需要判断数组元素是否都是同类型 2023/6/21
		if len(ele) > 1 {
			arrType := ele[0].Type()
			for idx, obj := range ele {
				if obj.Type() != arrType {
					return newError("array element must be same type. array type is %s, but element index at %d type is %s", arrType, idx, obj.Type())
				}
			}
		}
		return &object.Array{Elements: ele}
		// 求元组字面量的值, 将数组字面量转换为object.Tuple
	case *ast.TupleLiteral:
		ele := evalExpressions(node.Elements, env)
		if len(ele) == 1 && isError(ele[0]) {
			return ele[0]
		}
		return &object.Tuple{Elements: ele}
	// 索引运算符求值
	case *ast.IndexExpression:
		left := Eval(node.Left, env)
		if isError(left) {
			return left
		}
		index := Eval(node.Index, env)
		if isError(index) {
			return index
		}
		return evalIndexExpression(left, index)
	// 索引运算符赋值表达式求值
	case *ast.IndexAssignExpression:
		idxExp, ok := node.Left.(*ast.IndexExpression)
		if !ok {
			return newError("syntax error want index expression but got %T", node.Left)
		}
		obj := Eval(idxExp.Left, env)
		if isError(obj) {
			return obj
		}
		idx := Eval(idxExp.Index, env)
		if isError(idx) {
			return idx
		}
		val := Eval(node.Right, env)
		if isError(val) {
			return val
		}
		return evalIndexAssignExpression(obj, idx, val)
	// hash表求值
	case *ast.HashLiteral:
		return evalHashLiteral(node, env)
	}
	return nil
}

// evalHashLiteral 将hash字面量转换为object.Hash
func evalHashLiteral(hash *ast.HashLiteral, env *object.Environment) object.Object {
	pairs := make(map[object.HashKey]object.HashPair)
	for key, val := range hash.Pairs {
		k := Eval(key, env)
		if isError(k) {
			return k
		}
		hashK, ok := k.(object.Hashable)
		if !ok {
			return newError("unusable as hash key: %s", k.Type())
		}
		v := Eval(val, env)
		if isError(v) {
			return v
		}
		hash := hashK.HashKey()
		pairs[hash] = object.HashPair{Key: k, Value: v}
	}

	return &object.Hash{Pairs: pairs}
}

// evalTupleIndexExpression 元组索引运算符求值
func evalTupleIndexExpression(tuple, index object.Object) object.Object {
	tup := tuple.(*object.Tuple)
	idx := index.(*object.Integer).Value
	if idx >= int64(len(tup.Elements)) {
		return newError("Tuple index out of bounds. tuple is %s idx is %d", tup.Inspect(), idx)
	}
	if idx < 0 {
		return newError("Illegal access. Tuple index must be a positive integer. tuple is %s idx is %d", tup.Inspect(), idx)
	}
	return tup.Elements[idx]
}

// evalArrayIndexExpression 数组索引运算符求值
func evalArrayIndexExpression(array, index object.Object) object.Object {
	arr := array.(*object.Array)
	idx := index.(*object.Integer).Value
	if idx >= int64(len(arr.Elements)) {
		return newError("Array index out of bounds. array is %s idx is %d", arr.Inspect(), idx)
	}
	if idx < 0 {
		return newError("Illegal access. Array index must be a positive integer. array is %s idx is %d", arr.Inspect(), idx)
	}
	return arr.Elements[idx]
}

// evalHashIndexExpression hash索引运算符求值
func evalHashIndexExpression(left, idx object.Object) object.Object {
	hash := left.(*object.Hash)
	key, ok := idx.(object.Hashable)
	if !ok {
		return newError("unusable as hash key: %s", idx.Type())
	}
	pair, ok := hash.Pairs[key.HashKey()]
	if !ok {
		return NULL
	}
	return pair.Value
}

// evalHashIndexAssignExpression hash - 索引运算符赋值表达式求值
func evalHashIndexAssignExpression(hashObj, keyObj, newVal object.Object) object.Object {
	hash := hashObj.(*object.Hash)
	key, ok := keyObj.(object.Hashable)
	if !ok {
		return newError("unusable as hash key: %s", keyObj.Type())
	}
	hk := key.HashKey()
	pair, ok := hash.Pairs[hk]
	if !ok {
		return NULL
	}
	//old := pair.Value
	pair.Value = newVal
	hash.Pairs[hk] = pair
	return EMPTY
}

// evalArrayIndexAssignExpression 数组 - 索引运算符赋值表达式求值
func evalArrayIndexAssignExpression(array, index, newVal object.Object) object.Object {
	arr := array.(*object.Array)
	idx := index.(*object.Integer).Value
	if idx >= int64(len(arr.Elements)) {
		return newError("Array index out of bounds. array is %s idx is %d", arr.Inspect(), idx)
	}
	if idx < 0 {
		return newError("Illegal access. Array index must be a positive integer. array is %s idx is %d", arr.Inspect(), idx)
	}
	// old := arr.Elements[idx] // 本质上来讲这是一个赋值操作，不需要返回值，直接返回EMPTY就好了
	arr.Elements[idx] = newVal
	return EMPTY
}

// evalIndexAssignExpression 索引运算符赋值表达式求值
func evalIndexAssignExpression(obj, idx, val object.Object) object.Object {
	switch {
	case obj.Type() == object.ArrayObj:
		return evalArrayIndexAssignExpression(obj, idx, val)
	case obj.Type() == object.HashObj:
		return evalHashIndexAssignExpression(obj, idx, val)
	default:
		return newError("index assign operator not supported: %s", obj.Type())
	}
}

// evalIndexExpression 索引运算符求值
func evalIndexExpression(left, idx object.Object) object.Object {
	switch {
	case left.Type() == object.ArrayObj && idx.Type() == object.IntegerObj:
		return evalArrayIndexExpression(left, idx)
	case left.Type() == object.HashObj:
		return evalHashIndexExpression(left, idx)
	case left.Type() == object.TupleObj:
		return evalTupleIndexExpression(left, idx)
	default:
		return newError("index operator not supported: %s", left.Type())
	}
}

// unwrapReturnValue 解包returnValue. 否则returnValue可能会一直向上冒泡多个函数，并且停止对这些函数的求值。但是实际上想要的只是停止对最后调用的函数的求值。
func unwrapReturnValue(obj object.Object) object.Object {
	if returnVal, ok := obj.(*object.ReturnValue); ok {
		return returnVal.Value
	}
	return obj
}

// extendedFunctionEnv 创建函数内部上下文环境, 并将实参和形参绑定
func extendedFunctionEnv(fn *object.Function, args []object.Object) *object.Environment {
	env := object.NewEnclosedEnv(fn.Env)
	for idx, param := range fn.Parameters {
		env.Set(param.Value, args[idx])
	}
	return env
}

// applyFunction 执行函数 - 获取函数执行结果
func applyFunction(fn object.Object, args []object.Object) object.Object {
	switch fnType := fn.(type) {
	case *object.Function:
		extendedEnv := extendedFunctionEnv(fnType, args)
		eval := Eval(fnType.Body, extendedEnv)
		return unwrapReturnValue(eval)
	case *object.Builtin:
		if result := fnType.Fn(args...); result != nil {
			return result
		}
		return NULL
	default:
		return newError("not a function: %s", fn.Type())
	}
}

// evalExpression 解析表达式数组
func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Object {
	var objs []object.Object

	for _, exp := range exps {
		res := Eval(exp, env)
		if isError(res) {
			return []object.Object{res}
		}
		objs = append(objs, res)
	}

	return objs
}

// evalIdentifier 求标识符的值
func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object {
	if obj, ok := env.Get(node.Value); ok {
		return obj
	}
	// 如果当前函数的上下文环境中找不到对应的标识符，那么就尝试去内置函数中寻找
	if obj, ok := builtins[node.Value]; ok {
		return obj
	}
	return newError("identifier not found: %s", node.Value)
}

// isError 辅助函数，判断求出来的值是不是object.ErrorObj
func isError(obj object.Object) bool {
	if obj != nil {
		return obj.Type() == object.ErrorObj
	}
	return false
}

// evalBlockStatements 求 语句块的值
func evalBlockStatements(bs *ast.BlockStatement, env *object.Environment) object.Object {
	var result object.Object

	for _, st := range bs.Statements {
		result = Eval(st, env)

		if result != nil {
			rt := result.Type()
			if rt == object.ReturnValueObj || rt == object.ErrorObj {
				return result
			}
		}
	}

	return result
}

// evalIfExpression 求if表达式的值
func evalIfExpression(ife *ast.IFExpression, env *object.Environment) object.Object {
	condition := Eval(ife.Condition, env)
	if isError(condition) {
		return condition
	}
	// 如果是真值(即不为NULL也不为false) 那么就执行if语句块的内容
	if isTruthy(condition) {
		return Eval(ife.Consequence, env)
	} else if ife.Alternative != nil {
		// 如果不是真值，且存在else语句，那么就执行else语句
		return Eval(ife.Alternative, env)
	}
	// 否则返回NULL
	return NULL
}

// isTruthy 判断是否为真值(即不为NULL也不为false) - 真值返回true，否则返回false
func isTruthy(condition object.Object) bool {
	switch condition {
	case TRUE:
		return true
	case FALSE:
		return false
	case NULL:
		return false
	default:
		return true
	}
}

// evalIntegerInfixExpression 求 integer中缀表达式的值
func evalIntegerInfixExpression(left object.Object, operator string, right object.Object) object.Object {
	leftVal := left.(*object.Integer).Value
	rightVal := right.(*object.Integer).Value

	switch operator {
	case "+":
		return &object.Integer{Value: leftVal + rightVal}
	case "-":
		return &object.Integer{Value: leftVal - rightVal}
	case "*":
		return &object.Integer{Value: leftVal * rightVal}
	case "/":
		return &object.Integer{Value: leftVal / rightVal}
	case "<":
		return boolToBooleanObj(leftVal < rightVal)
	case ">":
		return boolToBooleanObj(leftVal > rightVal)
	case "==":
		return boolToBooleanObj(leftVal == rightVal)
	case "!=":
		return boolToBooleanObj(leftVal != rightVal)
	// 位运算操作
	case "&":
		return &object.Integer{Value: leftVal & rightVal}
	case "|":
		return &object.Integer{Value: leftVal | rightVal}
	case "^":
		return &object.Integer{Value: leftVal ^ rightVal}
	case "<<":
		if rightVal < 1 {
			return newError("unsupported operator: %s %s %s. %s operator right value must be > 0", left.Type(), operator, right.Type(), operator)
		}
		return &object.Integer{Value: leftVal << rightVal}
	case ">>":
		if rightVal < 1 {
			return newError("unsupported operator: %s %s %s. %s operator right value must be > 0", left.Type(), operator, right.Type(), operator)
		}
		return &object.Integer{Value: leftVal >> rightVal}
	case ">>>":
		if rightVal < 1 {
			return newError("unsupported operator: %s %s %s. %s operator right value must be > 0", left.Type(), operator, right.Type(), operator)
		}
		u := uint64(leftVal)
		return &object.Integer{Value: int64(u >> rightVal)}
	default:
		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
	}
}

// evalInfixExpression 求中缀表达式的值. 输入left左值，operator操作符，right右值
func evalInfixExpression(left object.Object, operator string, right object.Object) object.Object {
	switch {
	case left.Type() == object.IntegerObj && right.Type() == object.IntegerObj:
		return evalIntegerInfixExpression(left, operator, right)
	case left.Type() == object.StringObj && right.Type() == object.StringObj:
		return evalStringInfixExpression(left, operator, right)
	case left.Type() == object.BooleanObj && right.Type() == object.BooleanObj:
		if operator == "&&" {
			return boolToBooleanObj(booleanObjToBool(left.(*object.Boolean)) && booleanObjToBool(right.(*object.Boolean)))
		} else if operator == "||" {
			return boolToBooleanObj(booleanObjToBool(left.(*object.Boolean)) || booleanObjToBool(right.(*object.Boolean)))
		}
		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
	case operator == "==":
		return boolToBooleanObj(left == right)
	case operator == "!=":
		return boolToBooleanObj(left != right)
	case left.Type() != right.Type():
		return newError("type mismatch: %s %s %s", left.Type(), operator, right.Type())
	default:
		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
	}
}

// evalStringInfixExpression 求 字符串相加的值
func evalStringInfixExpression(left object.Object, operator string, right object.Object) object.Object {
	if operator != "+" {
		return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type())
	}
	leftVal := left.(*object.String).Value
	rightVal := right.(*object.String).Value
	return &object.String{Value: leftVal + rightVal}
}

// evalBangOperatorExpression 求 ! 符号表达式的值
func evalBangOperatorExpression(obj object.Object) object.Object {
	switch obj {
	case TRUE:
		return FALSE
	case FALSE:
		return TRUE
	case NULL:
		return TRUE
	default:
		return FALSE
	}
}

// evalMinusPrefixOperatorExpression 求 - 符号前缀表达式的值
func evalMinusPrefixOperatorExpression(obj object.Object) object.Object {
	if obj.Type() != object.IntegerObj {
		return newError("unknown operator: -%s", obj.Type())
	}
	value := obj.(*object.Integer).Value
	return &object.Integer{Value: -value}
}

// evalNotPrefixOperatorExpression 求 ~ 符号前缀表达式的值
func evalNotPrefixOperatorExpression(obj object.Object) object.Object {
	if obj.Type() != object.IntegerObj {
		return newError("unknown operator: ~%s", obj.Type())
	}
	val := obj.(*object.Integer).Value
	return &object.Integer{Value: ^val}
}

// evalPrefixExpression 解析前缀表达式. 这里是已经解析过一次了，operator 是操作符，right 是表达式的右值
func evalPrefixExpression(operator string, right object.Object) object.Object {
	switch operator {
	case "!":
		return evalBangOperatorExpression(right)
	case "-":
		return evalMinusPrefixOperatorExpression(right)
	case "~":
		return evalNotPrefixOperatorExpression(right)
	default:
		return newError("unknown operator: %s%s", operator, right.Type())
	}
}

// booleanObjToBool object.Boolean 转为 go 的 bool
func booleanObjToBool(obj *object.Boolean) bool {
	if obj == TRUE {
		return true
	}
	return false
}

// boolToBooleanObj go的bool转为object.Boolean
func boolToBooleanObj(b bool) *object.Boolean {
	if b {
		return TRUE
	}
	return FALSE
}

// evalProgram 遍历整颗AST树，对每一条语句都进行求值
func evalProgram(node *ast.Program, env *object.Environment) object.Object {
	var result object.Object

	for _, stmt := range node.Statements {
		result = Eval(stmt, env)

		switch result := result.(type) {
		case *object.ReturnValue:
			return result.Value
		case *object.Error:
			return result
		}
	}

	return result
}

// newError 构建一个object.Error指针
func newError(format string, a ...interface{}) *object.Error {
	return &object.Error{Message: fmt.Sprintf(format, a...)}
}
